package org.yacon;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Evgeny Vetrov
 */
class TypeConverterHelper
{
    private static final Map<String, TypeConverter> namedConverters = new HashMap<String, TypeConverter>();
    private static final Map<String, Class<? extends ParametrizedTypeConverter>> namedPatternsConverters =
            new HashMap<String, Class<? extends ParametrizedTypeConverter>>();

    static {
        namedConverters.put("int", new Converters.IntegerConverter());
        namedConverters.put("boolean", new Converters.BooleanConverter());
        namedConverters.put("double", new Converters.DoubleConverter());
        namedConverters.put("float", new Converters.FloatConverter());
        namedConverters.put("byte", new Converters.ByteConverter());
        namedConverters.put("char", new Converters.CharConverter());
        namedConverters.put("short", new Converters.ShortConverter());
        namedConverters.put("long", new Converters.LongConverter());
        namedPatternsConverters.put("date", Converters.DateConverter.class);
        namedPatternsConverters.put("pattern", Converters.PatternConverter.class);
    }

    private TypeConverterHelper()
    {
        throw new AssertionError();
    }

    static void applyConverter(Map<String, Object> parameterValues, Map<String, TypeConverter> converters)
    {
        for (Map.Entry<String, Object> entry : parameterValues.entrySet()) {
            TypeConverter converter = converters.get(entry.getKey());
            if (converter != null) {
                Object value = entry.getValue();
                if (value instanceof String) {
                    Object newValue;
                    try {
                        newValue = converter.convert(((String) value).trim());
                    }
                    catch (Exception e) {
                        throw new RuntimeException("Incorrect value for " + entry.getKey() + " parameter\n"
                                + e.getMessage(), e);
                    }
                    entry.setValue(newValue);
                }
            }
        }
    }

    @SuppressWarnings("unchecked")
    static <T> TypeConverter<T> getConverter(String typeName, Map<String, String> attrValues)
    {
        TypeConverter<T> converter = namedConverters.get(typeName);
        if (converter == null) {
            Class<? extends ParametrizedTypeConverter> converterClass = namedPatternsConverters.get(typeName);
            if (converterClass == null)
                throw new IllegalArgumentException("No TypeConverter for type name='" + typeName + "'");
            try {
                ParametrizedTypeConverter parametrizedConverter = converterClass.newInstance();
                parametrizedConverter.init(attrValues);
                return parametrizedConverter;
            }
            catch (InstantiationException e) {
                throw new RuntimeException(e);
            }
            catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        return converter;
    }

    static <T> TypeConverter<T> getConverter(Class<TypeConverter<T>> converterClass, Map<String, String> attrValues)
    {
        @SuppressWarnings("unchecked")
        TypeConverter<T> result = createConverterInstance(converterClass);
        if (result instanceof ParametrizedTypeConverter)
            ((ParametrizedTypeConverter) result).init(attrValues);
        return result;
    }

    private static <T> TypeConverter<T> createConverterInstance(Class<TypeConverter<T>> converterClass)
    {
        try {
            return converterClass.newInstance();
        }
        catch (InstantiationException e) {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}
